package world.snowcrystal.nova.scoring;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Component;
import world.snowcrystal.nova.model.dto.question.QuestionDto;
import world.snowcrystal.nova.model.entity.App;
import world.snowcrystal.nova.model.entity.Question;
import world.snowcrystal.nova.model.entity.ScoringResult;
import world.snowcrystal.nova.model.entity.UserAnswer;
import world.snowcrystal.nova.model.enums.AppScoringStrategyEnum;
import world.snowcrystal.nova.model.enums.AppScoringTypeEnum;
import world.snowcrystal.nova.model.vo.QuestionVO;
import world.snowcrystal.nova.service.QuestionService;
import world.snowcrystal.nova.service.ScoringResultService;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 评估可能包括测试，但也包括观察（正式、非正式）、访谈、行为、监测等方法。
 * 信息包括正式和非正式的观察、纸笔测试、学生在家庭作业、实验工作、研究论文、项目和口头提问中的表现、
 * 分析用户的记录。评估是一个过程，通过这个过程，信息是相对于一些已知的目标或目标。
 *
 * @see <a href="https://zhuanlan.zhihu.com/p/454727321">特征评鉴</a>
 */
@Component
public class CustomAssessmentScoringStrategy implements ScoringStrategy {

    @Resource
    private QuestionService questionService;


    @Resource
    private ScoringResultService scoringResultService;


    @Override
    public UserAnswer score(List<String> choices, App app) throws Exception {

        Long appId = app.getId();

        // 根据 App id 获取 题目以及评分信息
        final Question question = questionService.getOne(
                Wrappers.lambdaQuery(Question.class)
                        .eq(Question::getAppId, appId)
        );
        final List<ScoringResult> scoringResults = scoringResultService.list(Wrappers.lambdaQuery(ScoringResult.class)
                .eq(ScoringResult::getAppId, appId)
        );
        QuestionVO questionVO = QuestionVO.objToVo(question);
        final List<QuestionDto> questionContent = questionVO.getQuestionContent();

        // 选项记录 Option-Key ：出现次数
        final Map<String, Integer> resultMap = new HashMap<>();

        // 遍历题目列表
        for (QuestionDto questionDto : questionContent) {
            // 遍历答案列表
            for (String choice : choices) {
                // 遍历评分结果列表
                for (QuestionDto.Option option : questionDto.getOptions()) {
                    if (!option.getKey().equals(choice)) {
                        continue;
                    }
                    final String result = option.getResult();
                    if (!resultMap.containsKey(result)) {
                        resultMap.put(result, 0);
                    }
                    resultMap.put(result, resultMap.get(result) + 1);
                }
            }
        }


        // 根据选项记录获取结果
        int maxScore = 0;
        ScoringResult maxScoreResult = null;
        for (ScoringResult scoringResult : scoringResults) {
            List<String> resultProp = JSONUtil.toList(scoringResult.getResultProp(), String.class);

            // ["result1","result2"] -> [mapValue1,mapValue2] -> sum(mapValue1,mapValue2)

            final int sum = resultProp.stream()
                    .mapToInt(prop -> resultMap.getOrDefault(prop, 0))
                    .sum();
            if (sum >= maxScore) {
                maxScore = sum;
                maxScoreResult = scoringResult;
            }
        }

        assert maxScoreResult != null;
        // 构造返回值
        return UserAnswer.builder()
                .appId(appId)
                .appType(app.getAppType())
                .scoringStrategy(app.getScoringStrategy())
                .choices(JSONUtil.toJsonStr(choices))
                .resultId(maxScoreResult.getId())
                .resultDesc(maxScoreResult.getResultDesc())
                .resultName(maxScoreResult.getResultName())
                .resultPicture(maxScoreResult.getResultPicture())
                .build();
    }

    @Override
    public boolean isSupport(App app) {
        final Integer appType = app.getAppType();
        final Integer scoringStrategy = app.getScoringStrategy();
        if(ObjectUtil.isNull(scoringStrategy) && ObjectUtil.isNull(appType)){
            return false;
        }
        return appType.equals(AppScoringTypeEnum.ASSESSMENT.getValue())
                && scoringStrategy.equals(AppScoringStrategyEnum.CUSTOM.getValue());
    }
}
